%option 8bit
%option noyywrap nounput batch debug
%option never-interactive

%{
#include <stdlib.h>
#include <math.h>
#include "ParserDriver.h"
#include "cmd_parser.hpp"

#undef yywrap
#define yywrap() 1

typedef yy::cmd_parser::token token;
YY_BUFFER_STATE str_buffer;

namespace yy {
	struct symbol * symbol_;
}

extern void set_error(yy::location * l, std::string m);

#define yyterminate() return token::EOL
%}

%{
#define YY_USER_ACTION yylloc->columns(yyleng);
%}

EXP ([Ee][-+]?[0-9]+)
%%

%{
yylloc->step();
%}

"+" { return token::ADD; }
"-" { return token::SUB; }
"*" { return token::MUL; }
"/" { return token::DIV; }
"=" { return token::ASSIGN; }
"|" { return token::ABS; }
"," { return token::COMMA; }
";" { return token::SEMICOLON; }
"(" { return token::LEFTBRACKET; }
")" { return token::RIGHTBRACKET; }
"^" { return token::POWER; }


(>)     { yylval->fn = 1; return token::CMP; }
(<)     { yylval->fn = 2; return token::CMP; }
(<>)    { yylval->fn = 3; return token::CMP; }
(==)    { yylval->fn = 4; return token::CMP; }
(>=)    { yylval->fn = 5; return token::CMP; }
(<=)    { yylval->fn = 6; return token::CMP; }


(if)    { return token::IF; }
(then)  { return token::THEN; }
(else)  { return token::ELSE; }
(while) { return token::WHILE; }
(do)    { return token::DO; }
(let)   { return token::LET;}


(sqrt)  { yylval->fn = B_sqrt; return token::FUNC; }
(exp)   { yylval->fn = B_exp; return token::FUNC; }
(ln)   { yylval->fn = B_log; return token::FUNC; }
(sin)   { yylval->fn = B_sin; return token::FUNC; }
(cos)   { yylval->fn = B_cos; return token::FUNC; }
(tan)   { yylval->fn = B_tan; return token::FUNC; }
(plotf) { return token::PLOTF; }

(pi) {yylval->d = 3.14159; return token::NUMBER;}
(PI) {yylval->d = 3.14159; return token::NUMBER;}

[a-zA-Z][a-zA-Z0-9]* {

	yy::symbol_ = driver.lookup(yytext);

	if (yy::symbol_ != NULL)
	{
		yylval->s = yy::symbol_;
		return token::NAME;
	} 
	else 
	{
		set_error(yylloc, "stack overflow");
		return token::EOL;
	}
}

[0-9]+"."[0-9]*{EXP}? |
"."?[0-9]+{EXP}?     {  yylval->d = atof(yytext); return token::NUMBER; }

"//".* |
[ \t] { yylloc->step(); }

\n { yylloc->lines(1); yylloc->step(); }

\r { yylloc->lines(1); return token::EOL; }

. { 
	std::string error_msg("invalid character");
	set_error(yylloc, error_msg); 
	return token::EOL; 
  }
%%

void ParserDriver::scan_begin(const char * cmd)
{
    str_buffer = yy_scan_string(cmd);
}

void ParserDriver::scan_end ()
{
    yy_delete_buffer(str_buffer); 
}